【z3 实践】【buu】[GWCTF 2019]xxor

拖进 ida 中

[GWCTF 2019]xxor01

跟进 main

main

发现是输入的字符串经过一个 魔改 tea 加密与检查函数

跟进魔改 tea,发现只是将 delta 和异或部分多加了点东西

tea

跟进 sub_400700

sub400700

感觉要爆破

v6属性

因为 v6 是 int64,所以要设置成 64 位

爆破脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
from z3 import *

enc = [0]*6
for i in range(6):
enc[i] = BitVec('enc['+str(i)+']',64)
flag = BitVec('flag', 64)

s = Solver()
s.add(enc[2] - enc[3] == 0x84A236FF)
s.add(enc[3] + enc[4] == 0xFA6CB703)
s.add(enc[2] - enc[4] == 0x42D731A8)
s.add(enc[0] == 0xDF48EF7E)
s.add(enc[5] == 0x84F30420)
s.add(enc[1] == 0x20CAACF4)

if s.check() == sat:
# 如果有解,打印模型
print("6666")
m = s.model()
for i in range(6):
print("enc["+str(i)+"] =", hex(m[enc[i]].as_long()))

else:
print("wrong")

print (hex(0x458BCD42 * 64))#这是sum加密后的值

爆破完得到密文

进行解密

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include <iostream>
using namespace std;
// //加密函数
//void encrypt (uint32_t* v, uint32_t* k) {
// uint32_t v0=v[0], v1=v[1], sum=0, i; //v0,v1分别为字符串的低字节高字节
// uint32_t delta=0x458BCD42;
// uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3];
// for (i=0; i < 32; i++) { //加密32轮
// sum += delta;
// v0 += ((v1<<6) + k0) ^ (v1 + sum + 11) ^ ((v1>>9) + k1) ^ 0x20;
// v1 += ((v0<<6) + k2) ^ (v0 + sum + 20) ^ ((v0>>9) + k3) ^ 0x10;
// }
// v[0]=v0; v[1]=v1;//加密后再重新赋值
//}
//解密函数
void decrypt (uint32_t* v, uint32_t* k) {
uint32_t v0, v1;
uint32_t delta=0x458BCD42;
uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3];
for (int j = 0; j <= 4; j += 2)
{
uint32_t sum=0x458BCD42 * 0x40 ;
v0 = v[j];
v1 = v[j + 1];
for (int i=0; i<64; i++)
{ //解密时将加密算法的顺序倒过来,还有+=变为-=
v1 -= ((v0<<6) + k2) ^ (v0 + sum + 20) ^ ((v0>>9) + k3) ^ 0x10;
v0 -= ((v1<<6) + k0) ^ (v1 + sum + 11) ^ ((v1>>9) + k1) ^ 0x20;
sum -= delta;
}
v[j]=v0; v[j+1]=v1;//解密后再重新赋值
}
}

int main()
{
uint32_t v[6]={0xdf48ef7e,0x20caacf4,0xe0f30fd5,0x5c50d8d6,0x9e1bde2d,0x84f30420},k[4]={0x02,0x02,0x03,0x04};
// v为要加密的数据是两个32位无符号整数
// k为加密解密密钥,为4个32位无符号整数,即密钥长度为128位
// printf("加密前原始数据:%u %u\n",v[0],v[1]);
// encrypt(v, k);
// printf("加密后的数据:%u %u\n",v[0],v[1]);
decrypt(v, k);
for (int i = 0; i < 6; ++i) {
// cout << *((char*)&v[i] + 2) << *((char*)&v[i] + 1) << * ((char*)&v[i]); //这可以直接得出flag
printf("%llx", v[i]);//这得出的是16进制需要进行转换
}
return 0;
}

因为计算出来的是 16 进制,所以把 16 进制输出后需要进行转换称为字符串·